<PageCard className="mb-8">

# size

Provides data to change the size of a floating element.

<MiddlewareContainer>
  <MiddlewareBadge type="Visibility Optimizer" />
  <MiddlewareBadge type="Data Provider" />
</MiddlewareContainer>

<ShowFor packages={['core']}>

```js
import {size} from '@floating-ui/core';
```

</ShowFor>

<ShowFor packages={['dom']}>

```js
import {size} from '@floating-ui/dom';
```

</ShowFor>

<ShowFor packages={['react']}>

```js
import {size} from '@floating-ui/react';
```

</ShowFor>

<ShowFor packages={['react-dom']}>

```js
import {size} from '@floating-ui/react-dom';
```

</ShowFor>

<ShowFor packages={['vue']}>

```js
import {size} from '@floating-ui/vue';
```

</ShowFor>

<ShowFor packages={['react-native']}>

```js
import {size} from '@floating-ui/react-native';
```

</ShowFor>

This is useful to ensure the floating element isn't too big to
fit in the viewport (or more specifically, its clipping context),
especially when a maximum size isn't specified. It also allows
matching the width/height of the reference element.

</PageCard>

<div className="flex flex-col gap-4">
  <Chrome
    label="Scroll the container"
    center
    scrollable="y"
    className="h-96"
  >
    <Floating
      tooltipStyle={{
        height: 300,
        overflow: 'hidden',
        maxHeight: 0,
      }}
      middleware={[
        {
          name: 'size',
          options: {padding: 5, rootBoundary: 'document'},
        },
      ]}
    >
      <div className="grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000" />
    </Floating>
  </Chrome>
</div>

## Usage

If your floating element's content cannot be resized such as in
the example, you can make the floating element scrollable with
`overflow: scroll{:sass}` (or `auto{:.param}`). Ensure your CSS
is using `box-sizing: border-box{:sass}`!

<ShowFor packages={['core']}>

```js
computePosition(referenceEl, floatingEl, {
  middleware: [
    size({
      apply({availableWidth, availableHeight, elements}) {
        // Change styles
      },
    }),
  ],
});
```

</ShowFor>

<ShowFor packages={['dom']}>

```js
computePosition(referenceEl, floatingEl, {
  middleware: [
    size({
      apply({availableWidth, availableHeight, elements}) {
        // Change styles, e.g.
        Object.assign(elements.floating.style, {
          maxWidth: `${Math.max(0, availableWidth)}px`,
          maxHeight: `${Math.max(0, availableHeight)}px`,
        });
      },
    }),
  ],
});
```

</ShowFor>

<ShowFor packages={['vue']}>

```js
useFloating(reference, floating, {
  middleware: [
    size({
      apply({availableWidth, availableHeight, elements}) {
        // Change styles, e.g.
        Object.assign(elements.floating.style, {
          maxWidth: `${Math.max(0, availableWidth)}px`,
          maxHeight: `${Math.max(0, availableHeight)}px`,
        });
      },
    }),
  ],
});
```

</ShowFor>

<ShowFor packages={['react', 'react-dom']}>

```js
useFloating({
  middleware: [
    size({
      apply({availableHeight, elements}) {
        const value = `${Math.max(0, availableHeight)}px`;

        // 1. Assign directly:
        elements.floating.style.maxHeight = value;
        // 2. Or, use a CSS variable:
        elements.floating.style.setProperty(
          '--available-height',
          value,
        );
      },
    }),
  ],
});
```

</ShowFor>

## Options

These are the options you can pass to `size(){:js}`.

```ts
interface SizeOptions extends DetectOverflowOptions {
  apply?: (
    state: MiddlewareState & {
      availableWidth: number;
      availableHeight: number;
    },
  ) => void;
}
```

### `apply{:.function}`

default: `undefined{:js}`

Unlike other middleware, in which you assign styles after
`computePosition(){:js}` has done its work, `size(){:js}` has its
own `apply{:.function}` function to do the work during the
lifecycle:

```js
size({
  apply({availableWidth, availableHeight, ...state}) {
    // Style mutations here
  },
});
```

#### `availableWidth{:.param}`

Represents how wide the floating element can be before it will
overflow its clipping context. You'll generally set this as the
`maxWidth{:.key}` CSS property.

#### `availableHeight{:.param}`

Represents how tall the floating element can be before it will
overflow its clipping context. You'll generally set this as the
`maxHeight{:.key}` CSS property.

<Notice>
  Both properties can be negative. When applying max styles, you should clamp them above `0{:js}`.
</Notice>

#### ...middlewareState

See [MiddlewareState](/docs/middleware#middlewarestate).

Many useful properties are also accessible via this callback,
such as `rects{:.key}` and `elements{:.key}`.

### ...detectOverflowOptions

All of [`detectOverflow`](/docs/detectOverflow#options)'s options
can be passed. For instance:

```js
size({padding: 5}); // 0 by default
```

### Deriving options from state

You can derive the options from the
[middleware lifecycle state](/docs/middleware#middlewarestate):

```js
size((state) => ({
  padding: state.rects.reference.width,
}));
```

## Using with `flip(){:js}`

Using `size(){:js}` together with `flip(){:js}` enables some
useful behavior. The floating element can be resized, thus
allowing it to prefer its initial placement as much as possible,
until it reaches a minimum size, at which point it will flip.

If you're using the `padding{:.key}` option in either middleware,
ensure they share the **same value**.

### `bestFit{:.string}`

The `'bestFit'{:js}` fallback strategy in the `flip(){:js}`
middleware is the default, which ensures the best fitting
placement is used. In this scenario, place `size(){:js}`
**after** `flip(){:js}`:

```js
const middleware = [
  flip(),
  size({
    apply({availableWidth, availableHeight}) {
      // ...
    },
  }),
];
```

<div className="flex flex-col gap-4">
  <Chrome
    label="Scroll the container"
    center
    scrollable="y"
    className="h-96"
  >
    <Floating
      tooltipStyle={{
        height: 200,
        overflow: 'hidden',
        maxHeight: 0,
      }}
      middleware={[
        {
          name: 'flip',
          options: {padding: 5, rootBoundary: 'document'},
        },
        {
          name: 'size',
          options: {padding: 5, rootBoundary: 'document'},
        },
      ]}
    >
      <div className="grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000" />
    </Floating>
  </Chrome>
</div>

This strategy ensures the floating element stays in view at all
times at the most optimal size.

### `initialPlacement{:.string}`

If instead, you want the initial placement to take precedence,
and are setting a minimum acceptable size, place `size(){:js}`
**before** `flip(){:js}`:

```js {12}
const middleware = [
  size({
    apply({availableHeight, elements}) {
      Object.assign(elements.floating.style, {
        // Minimum acceptable height is 50px.
        // `flip` will then take over.
        maxHeight: `${Math.max(50, availableHeight)}px`,
      });
    },
  }),
  flip({
    fallbackStrategy: 'initialPlacement',
  }),
];
```

## Match reference width

A common feature of select dropdowns is that the dropdown matches
the width of the reference regardless of its contents. You can
also use `size(){:js}` for this, as the `Rect{:.class}`s get
passed in:

```js
size({
  apply({rects, elements}) {
    Object.assign(elements.floating.style, {
      minWidth: `${rects.reference.width}px`,
    });
  },
});
```

## Troubleshooting

### `maxHeight` style left on floating element

Leaving the `maxHeight` style on the floating element that's kept
mounted in the DOM when closed can cause issues in certain
situations where it can and should expand more.

By removing the style inside the `apply{:.function}` function
when the `scrollHeight` is less than the `availableHeight`, you
can prevent this:

```js
elements.floating.style.maxHeight =
  availableHeight >= elements.floating.scrollHeight
    ? ''
    : `${availableHeight}px`;
```
